from before_compute import *  # 计算前处理
from loop_compute import *  # 核心迭代计算
from plot import *  # 可视化处理
from load_plot_coutour import *  # 输出等高线图

import time


# 创建文件夹、复制参数文件至创建的文件夹中，返回文件夹名
def mkdir_cppar():
    from tkinter.filedialog import askdirectory
    import shutil
    print('请选择保存数据的文件夹：')
    folderName = askdirectory()
    if folderName == '':  # 若未选择文件夹，保存到临时目录中
        folderName = 'temp/data_out'
        makedirs(folderName)
    shutil.copy('template/inputdata/parameter.xlsx ',
                '{}/parameter.xlsx'.format(folderName))  # 复制输入的参数文件
    return folderName


# 带入计算的边界条件的选择
def number_of_boundary(second_computing, boundary, time_interval=3600):
    weather_data_count = len(boundary[0])  # 气候数据数量等于读取边界条件的长度
    n = int(second_computing // time_interval)  # 得到正在计算的时间段（第n个）
    n = n % weather_data_count  # 取余，进行整体的循环（当计算总时间大于边界条件总时间，从头循环）
    return n


# 开始计算
def start():
    # 1.读取计算参数
    time_step, time_count, loop_count, max_error, \
    s_coe_all, x_step, time_now, T, W, boundary_out, boundary_in = load_parameters('xlsx')
    time_total = time_step * time_count  # 计算模拟时间长度，用于进度表的显示

    # 2.设置储存数据的二维数据（行叠加），将初始温湿度场数据储存起来，增加时间项，增加内外传热传质量
    data_T = np.hstack((time_now, T, 0, 0))
    data_W = np.hstack((time_now, W, 0, 0))

    # 3.开始循环计算
    print('*********程序开始计算***********')
    start = time.clock()  # 开始计时
    time_counter = start
    fresh_time = 1
    # 外循环：时间循环
    for i in range(int(time_count)):
        # 3.1 迭代计算前的数据处理
        second = (i + 1) * time_step + time_now  # 得到正在计算的时刻
        # 室内外边界条件的选择
        n_out = number_of_boundary(second, boundary_out, 3600)
        n_in = number_of_boundary(second, boundary_in, 3600)

        # 3.2 核心计算部分，通过compute_loop函数进行迭代计算
        # 输入参数主要为：上一时刻温度场，上一时刻湿度场，墙体材料参数，i时刻的边界条件
        T, W, q_out, q_in, j_out, j_in = compute_loop(loop_count, x_step, time_step, max_error, T, W,
                                                      s_coe_all, boundary_out[1:, n_out], boundary_in[1:, n_in])

        # 3.3 显示整体的计算进度
        if time.clock() - time_counter > fresh_time:  # 每隔fresh_time ，打印一次
            progress = (i + 1) / time_count * 100  # 计算整体进度%
            compute_rate = (second - time_now) / time.clock()  # 定义计算速率，提示计算时间
            remaining = (time_total + time_now - second) // compute_rate  # 计算剩余的时间

            print('正在计算时刻：%s' % second2date(second))  # 输出正在计算的时刻
            print('程序总进度：%.1f%%' % progress)  # 显示整体进度%
            print('计算速率为：%.2f' % compute_rate)  # 显示计算的速率
            print('*' * 20 + '预计还需要计算{}'.format(second2date(remaining)) +
                  '*' * 20 + '已运行%s' % second2date(int(time.clock())))  # 显示剩余的时间

            time_counter = time.clock()  # 更新计数时间

        # 3.4 储存数据
        # 判断1：总时间大于24小时，每小时储存一次
        judge_1 = (time_total > 24 * 3600) and (second % 3600 == 0)
        # 判断2：总时间小于24小时大于12小时，每二十分钟储存一次
        judge_2 = (24 * 3600 >= time_total > 12 * 3600) and (second % 1200 == 0)
        # 判断3：总时间小于12小时大于1小时，每五分钟储存一次
        judge_3 = (12 * 3600 >= time_total > 1 * 3600) and (second % 300 == 0)
        # 判断4：总时间小于1小时大于0.5小时，每分钟储存一次
        judge_4 = (1 * 3600 >= time_total > 0.5 * 3600) and (second % 60 == 0)
        # 判断5：总时间小于0.5小时，都储存
        judge_5 = (0.5 * 3600 >= time_total)
        # 综合
        judge = judge_1 or judge_2 or judge_3 or judge_4 or judge_5
        # 上述条件成立时，储存数据
        if judge:
            data_T = np.row_stack([data_T, np.hstack((second, T, q_out, q_in))])
            data_W = np.row_stack([data_W, np.hstack((second, W, j_out, j_in))])

    # 3.4 主体计算完毕，计时
    end = time.clock()
    t_compute = end - start
    print('计算程序完成，计算总时长：', second2date(t_compute))

    return data_T, data_W, t_compute, x_step


# 保存数据
def savedata(folderName, data_T, data_W, t_compute, x_step):
    # 保存计算所花的时间
    np.savetxt('{}/{}.txt'.format(folderName, 'computed_time'),
               [second2date(t_compute), t_compute], fmt='%s', delimiter=',')
    # 4.输出并保存数据
    makedirs(folderName)
    # 4.1 温湿度场计算
    T_total = data_T[:, :-2]
    W_total = data_W[:, :-2]
    # 计算水蒸气分压力
    p = rh2pressure(T_total[:, 1:], W_total[:, 1:])
    P_total = np.hstack((T_total[:, 0].reshape(-1, 1), p))
    # 温湿度转化：绝对温度转化为摄氏温度，湿度转化为百分数
    T_total[:, 1:] -= 273.15
    W_total[:, 1:] *= 100
    title = np.hstack((t_compute, x_step))  # 表头：包括总计算时间，及各段网格大小
    T_total = np.row_stack([title, T_total])
    W_total = np.row_stack([title, W_total])
    P_total = np.row_stack([title, P_total])
    # 4.2 传热传质量数据
    q_total = np.hstack((data_T[:, :1], data_T[:, -2:]))
    j_total = np.hstack((data_W[:, :1], data_W[:, -2:]))

    # 4.3 保存成文件
    # 保存的数据整理
    fileName = ['温度场', '湿度场', '分压力场', '传热量', '传质量']
    unit = ['℃', '%', 'Pa', 'W/m2', 'kg/m2•s']
    data = [T_total, W_total, P_total, q_total, j_total]

    print('正在保存数据...')
    for n in range(5):
        np.savetxt('{}/data_{}.csv'.format(folderName, fileName[n]),
                   data[n], fmt='%.12f', delimiter=',')
    print('数据保存完成！')

    # 4.3 数据可视化
    # 4.3.1 保存曲线图
    print('正在输出定性曲线图表......')
    fig_curve_P = plot_chart(P_total, '分压力场', 'Pa')  # 输出水蒸气分压力场图表
    fig_curve_T = plot_chart(T_total, '温度场', '℃')  # 输出温度场图表
    fig_curve_W = plot_chart(W_total, '湿度场', '%')  # 输出湿度场图表
    print('********输出图表完成！**********')
    fig = [fig_curve_T, fig_curve_W, fig_curve_P]
    # 保存图表图片
    for n in range(3):
        fig[n].savefig('{}/curve_{}.png'.format(folderName, fileName[n]))
    # 4.4.2 保存等高线图
    field_style = ['t', 'rh', 'p']
    layers_thickness = readExcel('{}/parameter.xlsx'.format(folderName), 'wall')[1][1:-1]
    for n in range(3):
        filename = '{}/data_{}.csv'.format(folderName, fileName[n])
        style = field_style[n]
        plot_field_contour(filename, style, layers_thickness)
        plt.savefig('{}/contour_{}.png'.format(folderName, fileName[n]), dpi=350)


if __name__ == '__main__':
    print('程序开始：')
    folderName = mkdir_cppar()  # 创建文件夹，复制计算参数，返回文件夹路径
    data_T, data_W, t_compute, x_step = start()  # 开始计算，返回相关参数用于数据保存用
    savedata(folderName, data_T, data_W, t_compute, x_step)  # 保存数据
    print('程序结束！')

